package com.zues.thread.aqs;

import com.zues.thread.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName CyclicBarrierDemo
 * @Description 测试学习循环栅栏
 * 循环屏障，用来进行线程协作，等待线程满足某个计数，才能触发自己执行
 * @Author zeus
 * @Date 4/2/2025 10:36 上午
 * @Version 1.0
 **/
@Slf4j(topic = "c.CyclicBarrierDemo")
public class CyclicBarrierDemo {


    public static void main(String[] args) {
//        test1();

//        multiStage();

        exceptionHandlingDemo();

    }

    /**
     * 测试1：
     * 循环栅栏，用来进行线程协作，等待线程满足某个计数，才能触发自己执行
     * 线程池核心数量与循环栅栏数量需要一致，否则无法触发Task1,Task2，多线程情况下有可能有两个Task1执行
     */
    private static void test1() {
        // 线程池核心数量与循环栅栏数量需要一致，否则无法触发Task1,Task2，多线程情况下有可能有两个Task1执行
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CyclicBarrier barrier = new CyclicBarrier(2, () -> log.debug("Task1,Task2      finish"));

        // 循环使用
        for (int i = 0; i < 3; i++) {
            // 提交 Task1 任务到线程池
            executorService.submit(() -> {
                try {
                    log.debug("Task1  begin...");
                    // 模拟任务执行耗时
                    ThreadUtil.sleep(2);
                    // 等待其他线程到达屏障
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    // 若发生异常，抛出运行时异常
                    throw new RuntimeException(e);
                }
            }, "Task1");

            // 提交 Task2 任务到线程池
            executorService.submit(() -> {
                try {
                    log.debug("Task2  begin...");
                    // 模拟任务执行耗时
                    ThreadUtil.sleep(2);
                    // 等待其他线程到达屏障
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    // 若发生异常，抛出运行时异常
                    throw new RuntimeException(e);
                }
            }, "Task2");
        }

        // 关闭线程池，不再接受新任务
        executorService.shutdown();
    }

    /**
     * 测试2：
     * 多阶段游戏加载
     */
    private static void multiStage(){
        final int players = 3;
        CyclicBarrier barrier = new CyclicBarrier(players,
                () -> log.debug("所有玩家都已准备完毕，开始游戏"));

        ExecutorService executorService = Executors.newFixedThreadPool(players);

        for (int stage = 1; stage <= 3; stage++) {
            int finalStage = stage;
            for (int i = 0; i < players; i++) {
                int playerId = i + 1;
                executorService.submit(()->{
                    try {
                        log.debug("玩家{} 正在加载第{}关资源...", playerId, finalStage);
                        ThreadUtil.sleep(new Random().nextInt(3));
                        barrier.await();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                });
            }
            ThreadUtil.sleep(3);//等待关卡切换
        }
        executorService.shutdown();


    }

    /**
     * 测试3：
     * 异常处理示例演示了当某个线程失败时，如何重置屏障并处理 BrokenBarrierException
     */
    public static void exceptionHandlingDemo() {
        final int workerCount = 2;
        CyclicBarrier barrier = new CyclicBarrier(workerCount, () ->
                log.debug("所有工作完成，开始数据提交"));

        ExecutorService service = Executors.newFixedThreadPool(workerCount);

        for (int i = 0; i < workerCount; i++) {
            int workerId = i + 1;
            service.submit(() -> {
                try {
                    log.debug("工人{} 开始处理数据", workerId);
                    if (workerId == 1) {
                        ThreadUtil.sleep(3);
                        throw new RuntimeException("数据损坏异常");
                    }
                    barrier.await();
                } catch (Exception e) {
                    log.error("工人{} 处理失败: {}", workerId, e.getMessage());
                    barrier.reset(); // 重置屏障
                }
                return null;
            });
        }
        service.shutdown();
    }

}
